String clazzTpl({package}) => """
import 'dart:io';
import 'dart:math';
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter/foundation.dart';
import 'package:path_provider/path_provider.dart';
import 'package:$package/route/main.route.dart';
import 'package:$package/utils/print_util.dart';
import 'package:$package/utils/screen_util.dart';
import 'package:$package/store/app_config/app_config_state.dart';

class SysErrorUtil {
  static bool _writeFile(Map<String, String> map) {
    if (map['content'] != null && (map['content'] as String).isNotEmpty) {
      File(map['path']!)
        ..createSync(recursive: true)
        ..writeAsStringSync(map['content']!, flush: true);
      return true;
    }
    return false;
  }

  static Future<bool> _writeErrorLog(String path, String content) async {
    return compute(_writeFile, {'path': path, 'content': content});
  }

  static void writeErrorLog(Object error, StackTrace stackTrace) async {
    // 控制台输出
    if (kDebugMode) {
      final errList =
          _errorText(error.toString(), stackTrace: stackTrace.toString());
      logDebugPrint(errList.join("\\n"));
    }
    // 写入日志文件
    StringBuffer sb = StringBuffer();
    final errorList =
        _errorText(error.toString(), stackTrace: stackTrace.toString());
    for (var element in errorList) {
      sb.writeln(element);
    }
    String appDir = (await getApplicationDocumentsDirectory()).path;
    final now = DateTime.now();
    String dateDir = ['\${now.year}年', '\${now.month}月', '\${now.day}日']
        .join(Platform.pathSeparator);
    String fileName =
        '\${now.hour}时\${now.minute}分\${now.second}秒\${now.microsecond}.log';
    _writeErrorLog(
        '\$appDir\${Platform.pathSeparator}\$dateDir\${Platform.pathSeparator}\$fileName',
        sb.toString());
  }

  static void onError(FlutterErrorDetails details) async {
    Zone.current.handleUncaughtError(
        details.exception, details.stack ?? StackTrace.empty);
  }

  static List<String> _errorText(String error, {String? stackTrace}) {
    return [
      'App设备信息========================',
      'deviceId:\${AppAndDevice.deviceId}',
      'deviceType:\${AppAndDevice.deviceType}',
      'deviceVersion:\${AppAndDevice.deviceVersion}',
      'appVersion:\${AppAndDevice.appVersion}',
      'appBuildNumber:\${AppAndDevice.appBuildNumber}',
      '\\n\\nError========================',
      error,
      '\\n\\nStackTrace===================',
      if (stackTrace != null) stackTrace,
    ];
  }

  static Widget builder(FlutterErrorDetails details) {
    final errorList = _errorText(details.exceptionAsString());
    if (details.stack != null) {
      errorList.addAll(details.stack.toString().split('\\n'));
    }
    bool isShow = !kDebugMode;
    getSlivers() {
      if (isShow) {
        return [
          SliverFillRemaining(
            child: Builder(builder: (context) {
              return Column(
                children: [
                  SizedBox(
                    height: MediaQuery.of(context).padding.top + 200.px,
                  ),
                  const Icon(
                    Icons.vpn_lock_rounded,
                    size: 300,
                  ),
                  Padding(
                    padding: EdgeInsets.only(
                      top: 40.px,
                      bottom: 60.px,
                    ),
                    child: Text(
                      "页面去了外太空…",
                      style: TextStyle(
                        color: const Color(0xFF60626A),
                        fontSize: 28.sp,
                      ),
                    ),
                  ),
                  InkWell(
                    onTap: () => Navigator.popUntil(
                        context, ModalRoute.withName(RouteConstant.MainPage)),
                    child: Container(
                      width: 265.px,
                      height: 80.px,
                      decoration: BoxDecoration(
                        gradient: const LinearGradient(
                          colors: [
                            Color(0xFFFE9D48),
                            Color(0xFFFF761F),
                          ],
                        ),
                        borderRadius: BorderRadius.circular(10.px),
                      ),
                      child: Center(
                        child: Text(
                          "回到首页",
                          style: TextStyle(
                            color: Colors.white,
                            fontSize: 32.sp,
                          ),
                        ),
                      ),
                    ),
                  )
                ],
              );
            }),
          ),
        ];
      }
      return [
        SliverPersistentHeader(
          pinned: false,
          floating: false,
          delegate: _SliverAppBarDelegate(
            minHeight: 20,
            maxHeight: 50,
            child: LayoutBuilder(builder: (context, constraints) {
              return Container(
                color: const Color(0xff3c3f41),
                padding:
                    EdgeInsets.only(top: MediaQuery.of(context).padding.top),
                child: Icon(
                  Icons.error,
                  color: Colors.red,
                  size: constraints.biggest.height,
                ),
              );
            }),
          ),
        ),
        SliverPadding(
          padding: EdgeInsets.only(top: 80.px),
          sliver: SliverList(
            delegate: SliverChildBuilderDelegate(
              (BuildContext context, int index) {
                return Container(
                  padding: const EdgeInsets.all(8),
                  color: index % 2 == 0 ? Colors.transparent : Colors.white24,
                  child: Text(
                    errorList[index],
                    style: const TextStyle(
                      color: Colors.white,
                      fontSize: 16,
                    ),
                  ),
                );
              },
              childCount: errorList.length,
            ),
          ),
        ),
      ];
    }

    return Scaffold(
      backgroundColor: isShow ? Colors.white : const Color(0xff3c3f41),
      body: Material(
        color: isShow ? Colors.white : const Color(0xff3c3f41),
        child: CustomScrollView(
          slivers: getSlivers(),
        ),
      ),
    );
  }
}

class _SliverAppBarDelegate extends SliverPersistentHeaderDelegate {
  _SliverAppBarDelegate({
    required this.minHeight,
    required this.maxHeight,
    required this.child,
  });

  final double minHeight;
  final double maxHeight;
  final Widget child;

  @override
  Widget build(
      BuildContext context, double shrinkOffset, bool overlapsContent) {
    return SizedBox.expand(child: child);
  }

  @override
  double get maxExtent => max(maxHeight, minHeight);

  @override
  double get minExtent => minHeight;

  @override
  bool shouldRebuild(covariant SliverPersistentHeaderDelegate oldDelegate) {
    return this != oldDelegate;
  }
}
""";
